<html lang="en">
	<head>
		<title>Yuka | Fuzzy Logic</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link rel="stylesheet" type="text/css" href="../lib/styles.css">
		<link rel="shortcut icon" type="image/x-icon" href="https://mugen87.github.io/yuka/favicon.ico">
		<style>
			#status {
				position: absolute;
				display: flex;
				align-items: center;
				justify-content: center;
				font-size: 28px;
				color: #ffffff;
				text-align: center;
				line-height: 20px;
				width: 100%;
				bottom: 0;
			}
			#status>div {
				background-color: #282828;
				width: 400px;
				padding: 16px;
			}
			#status>div>span {
				display: inline-block;
			}
		</style>
	</head>
<body>

	<section id="loading-screen">
		<div class="spinner">
			<div class="rect1"></div>
			<div class="rect2"></div>
			<div class="rect3"></div>
			<div class="rect4"></div>
			<div class="rect5"></div>
		</div>
	</section>

	<section id="info">
		<p>
			The soldier uses fuzzy inference to determine the best weapon<br/>
			based on the distance to the enemy and the available ammo.
		</p>
	</section>

	<section id="status">
		<div>
			<span>Current Weapon:</span>
			<span id="currentWeapon"></span>
		</div>
	</section>

	<script type="module">

		import * as YUKA from '../../build/yuka.module.js';
		import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.109/build/three.module.js';
		import * as DAT from 'https://cdn.jsdelivr.net/npm/dat.gui@0.7.7/build/dat.gui.module.js';
		import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.109/examples/jsm/loaders/GLTFLoader.js';

		import { Soldier } from './src/Soldier.js';


		let camera, scene, renderer, mixers = [];

		let entityManager, time;

		let soldier, zombie, assaultRifle, shotgun;

		const params = {
			distance: 8,
			ammoShotgun: 12,
			ammoAssaultRifle: 30
		};

		init();

		function init() {

			scene = new THREE.Scene();
			scene.background = new THREE.Color( 0xa0a0a0 );
			scene.fog = new THREE.Fog( 0xa0a0a0, 20, 40 );

			camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 200 );
			camera.position.set( - 0.5, 2, - 2.5 );
			camera.lookAt( 0, 0, 15 );

			//

			const geometry = new THREE.PlaneBufferGeometry( 150, 150 );
			const material = new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } );

			const ground = new THREE.Mesh( geometry, material );
			ground.rotation.x = - Math.PI / 2;
			ground.matrixAutoUpdate = false;
			ground.receiveShadow = true;
			ground.updateMatrix();
			scene.add( ground );

			//

			const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444, 0.6 );
			hemiLight.position.set( 0, 100, 0 );
			hemiLight.matrixAutoUpdate = false;
			hemiLight.updateMatrix();
			scene.add( hemiLight );

		 	const dirLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
			dirLight.position.set( - 10, 10, 10 );
			dirLight.matrixAutoUpdate = false;
			dirLight.updateMatrix();
			dirLight.castShadow = true;
			dirLight.shadow.camera.top = 2;
			dirLight.shadow.camera.bottom = - 2;
			dirLight.shadow.camera.left = - 10;
			dirLight.shadow.camera.right = 10;
			dirLight.shadow.camera.near = 0.1;
			dirLight.shadow.camera.far = 20;
			dirLight.shadow.mapSize.x = 2048;
			dirLight.shadow.mapSize.y = 2048;
			dirLight.target.position.set( 0, 0, 10 );
			scene.add( dirLight, dirLight.target );

			// scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) );

			scene.add( new THREE.PolarGridHelper( 20, 20 ) );

			//

			const loadingManager = new THREE.LoadingManager( () => {

				const loadingScreen = document.getElementById( 'loading-screen' );

				loadingScreen.classList.add( 'fade-out' );
				loadingScreen.addEventListener( 'transitionend', onTransitionEnd );

				//

				const rightHand = soldier._renderComponent.getObjectByName( 'Armature_mixamorigRightHand' );
				rightHand.add( assaultRifle );
				rightHand.add( shotgun );

				soldier.assaultRifle = assaultRifle;
				soldier.shotgun = shotgun;

				zombie.lookAt( soldier.position );

				//

				initUI();
				animate();

			} );

			const glTFLoader = new GLTFLoader( loadingManager );

			// load soldier

			glTFLoader.load( 'model/soldier.glb', ( gltf ) => {

				// add object to scene

				const renderComponent = gltf.scene;
				renderComponent.animations = gltf.animations;
				renderComponent.matrixAutoUpdate = false;

				renderComponent.traverse( ( object ) => {

					if ( object.isMesh ) {

						object.material.side = THREE.DoubleSide;
						object.castShadow = true;
						object.matrixAutoUpdate = false;

					}

				} );

				const mixer = new THREE.AnimationMixer( renderComponent );
				mixers.push( mixer );

				const idleAction = mixer.clipAction( 'Character_Idle' );
				idleAction.play();

				//

				soldier = new Soldier();
				soldier.rotation.fromEuler( 0, Math.PI * - 0.05, 0 );
				soldier.setRenderComponent( renderComponent, sync );

				entityManager.add( soldier );
				scene.add( renderComponent );

			} );

			// load zombie

			glTFLoader.load( 'model/zombie.glb', ( gltf ) => {

				const renderComponent = gltf.scene;
				renderComponent.animations = gltf.animations;
				renderComponent.matrixAutoUpdate = false;

				renderComponent.traverse( ( object ) => {

					if ( object.isMesh ) {

						object.material.side = THREE.DoubleSide;
						object.castShadow = true;
						object.matrixAutoUpdate = false;

					}

				} );

				//

				const mixer = new THREE.AnimationMixer( renderComponent );
				mixers.push( mixer );

				const idleAction = mixer.clipAction( 'Character_Idle' );
				idleAction.play();

				//

				zombie = new YUKA.GameEntity();
				zombie.name = 'zombie';
				zombie.position.set( 0, 0, params.distance );
				zombie.setRenderComponent( renderComponent, sync );

				entityManager.add( zombie );
				scene.add( renderComponent );

			} );

			// load shotgun

			glTFLoader.load( '../playground/hideAndSeek/model/shotgun.glb', ( gltf ) => {

				shotgun = gltf.scene;
				shotgun.traverse( ( object ) => {

					if ( object.isMesh ) object.castShadow = true;

				} );
				shotgun.scale.set( 0.35, 0.35, 0.35 );
				shotgun.rotation.set( Math.PI * 0.5, Math.PI * - 0.45, 0.1 );
				shotgun.position.set( - 50, 300, 0 );

			} );

			// load assault rifle

			glTFLoader.load( 'model/assaultRifle.glb', ( gltf ) => {

				assaultRifle = gltf.scene;
				assaultRifle.traverse( ( object ) => {

					if ( object.isMesh ) object.castShadow = true;

				} );
				assaultRifle.scale.multiplyScalar( 150 );
				assaultRifle.rotation.set( Math.PI * 0.45, Math.PI * 0.55, 0 );
				assaultRifle.position.set( - 30, 200, 70 );

			} );

			//

			renderer = new THREE.WebGLRenderer( { antialias: true } );
			renderer.setPixelRatio( window.devicePixelRatio );
			renderer.setSize( window.innerWidth, window.innerHeight );
			renderer.gammaOutput = true;
			renderer.gammaFactor = 2.2;
			renderer.shadowMap.enabled = true;
			document.body.appendChild( renderer.domElement );

			//

			window.addEventListener( 'resize', onWindowResize, false );

			// game setup

			entityManager = new YUKA.EntityManager();
			time = new YUKA.Time();

		}

		function onWindowResize() {

			camera.aspect = window.innerWidth / window.innerHeight;
			camera.updateProjectionMatrix();

			renderer.setSize( window.innerWidth, window.innerHeight );

		}

		function initUI() {

			const gui = new DAT.GUI( { width: 400 } );

			gui.add( params, 'distance', 5, 20 ).name( 'Distance To Enemy' ).onChange( ( value ) => {

				zombie.position.z = value;

			} );

			gui.add( params, 'ammoShotgun', 0, 12 ).step( 1 ).name( 'Ammo Shotgun' ).onChange( ( value ) => {

				soldier.ammoShotgun = value;

			} );

			gui.add( params, 'ammoAssaultRifle', 0, 30 ).step( 1 ).name( 'Ammo Assault Rifle' ).onChange( ( value ) => {

				soldier.ammoAssaultRifle = value;

			} );

		}

		function animate() {

			requestAnimationFrame( animate );

			const delta = time.update().getDelta();

			if ( mixers.length > 0 ) {

				for ( let i = 0, l = mixers.length; i < l; i ++ ) {

					mixers[ i ].update( delta );

				}

			}

			entityManager.update( delta );

			renderer.render( scene, camera );

		}

		function onTransitionEnd( event ) {

			event.target.remove();

		}

		function sync( entity, renderComponent ) {

			renderComponent.matrix.copy( entity.worldMatrix );

		}

	</script>

</body>
</html>
